﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Fine.Collections.Const;
using JetBrains.Annotations;



namespace Crocodile.LangUtils
{
    public static class EnumerableExt
    {


        public static IEnumerable<T> Safe<T>(this IEnumerable<T> sequence)
        {
            return sequence ?? CC0.ListOf<T>();
        }


        public static void ForEach<T>([CanBeNull] this IEnumerable<T> sequence, [NotNull] Action<T> action)
        {
            if (sequence != null)
                foreach (var item in sequence)
                    action(item);
        }


        public static void ProcessAll<T>([CanBeNull] this IEnumerable<T> sequence,
                                         [CanBeNull] Action<T> itemAction,
                                         [CanBeNull] Action startingAction = null,
                                         [CanBeNull] Action intermediateAction = null,
                                         [CanBeNull] Action finishingAction = null,
                                         [CanBeNull] Action emptyAction = null)
        {
            bool begin = true;

            foreach (var item in sequence ?? Enumerable.Empty<T>())
            {
                if (begin)
                {
                    begin = false;
                    if (startingAction != null)
                        startingAction();
                }
                else
                {
                    if (intermediateAction != null)
                        intermediateAction();
                }

                if (itemAction != null)
                {
                    itemAction(item);
                }
            }

            if (begin)
            {
                if (emptyAction != null)
                    emptyAction();
            }
            else
            {
                if (finishingAction != null)
                    finishingAction();
            }
        }


        public static string JoinAll<T>([CanBeNull] this IEnumerable<T> sequence,
                                        [NotNull] Func<T,string> itemToString,
                                        [NotNull] string head = "",
                                        [NotNull] string delimiter = "",
                                        [NotNull] string tail = "",
                                        [NotNull] string empty = "")
        {
            var buf = new StringBuilder();
            sequence.ProcessAll( item => buf.Append(itemToString(item)),
                                 () => buf.Append(head),
                                 () => buf.Append(delimiter),
                                 () => buf.Append(tail),
                                 () => buf.Append(empty)
                                );
            return buf.ToString();
        }

        

        public static IEnumerable<ObjectAndMatch<T>> ForMatches<T> (
                    this IEnumerable<T> sequence, 
                    Func<T,string> objectToString,
                    [NotNull] Regex pattern)
        {
            return from obj in sequence 
                   let match = objectToString(obj).Matches(pattern) 
                   where match != null 
                   select new ObjectAndMatch<T>{Object = obj, Match = match};
        }


        public struct ObjectAndMatch<T>
        {
            public T Object;
            public Match Match;
        }
                                 
  
    }
}
